// Widget factory that can be modified for child widgets.
// Copyright 2005 (C) Ralph Thomas

#include <view/factory.h>
#include <view/image.h>
#include <view/icon.h>
#include <view/scroll.h>
#include <view/generator.h>
#include <view/dynamic_text.h>
#include <view/item.h>
#include <view/table.h>
#include <view/toggle_button.h>
#include <view/rating.h>
#include <view/styled_button.h>
#include <view/optional.h>
#include <view/file_button.h>
#include <view/pump_holder.h>
#include <model/proxy/proxy.h>
#include <boost/bind.hpp>
#include <factory.hpp>

//
/// Default factory for creating non-clever widgets.
//
adobe::widget_node_t default_factory(
	adobe::name_t			name,
	const adobe::dictionary_t&	parameters,
	const adobe::widget_node_t&	parent,
	const adobe::factory_token_t&	token )
{
	if( name == adobe::static_name_t( "model_proxy" ) )
		return model::model_proxy_factory( parameters, parent, token );
	if( name == adobe::static_name_t( "image" ) )
		return view::image_factory( parameters, parent, token );
	if( name == adobe::static_name_t( "icon" ) )
		return view::icon_factory( parameters, parent, token );
	if( name == adobe::static_name_t( "item" ) )
		return view::item_factory( parameters, parent, token );
	if( name == adobe::static_name_t( "table" ) )
		return view::table_factory( parameters, parent, token );
	if( name == adobe::static_name_t( "dynamic_text" ) )
		return view::dynamic_text_factory( parameters, parent, token );
	if( name == adobe::static_name_t( "toggle_button" ) )
		return view::toggle_button_factory( parameters, parent, token );
	if( name == adobe::static_name_t( "rating" ) )
		return view::rating_factory( parameters, parent, token );
	if( name == adobe::static_name_t( "styled_button" ) )
		return view::styled_button_factory( parameters, parent, token );
	if( name == adobe::static_name_t( "optional" ) )
		return view::optional_factory( parameters, parent, token );
	if( name == adobe::static_name_t( "file_button" ) )
		return view::file_button_factory( parameters, parent, token, false );
	if( name == adobe::static_name_t( "directory_button" ) )
		return view::file_button_factory( parameters, parent, token, true );
	if( name == adobe::static_name_t( "datapump_holder" ) )
		return view::pump_holder_factory( parameters, parent, token );
	return adobe::default_factory( name, parameters, parent, token );
}

namespace view {
	void factory::push( const factory::factory_t& f ) {
		_factories.push_back( f );
	}
	void factory::pop() {
		_factories.pop_back();
	}
	factory::factory_t factory::top( const adobe::factory_token_t& token ) const {
		//
		// Make a factory_token_ptr_t that has all of the pointers
		// that have been set so far (which might mean all NULL).
		//
		factory_t f( factory_token_ptr_t(), default_factory );
		//
		// Fill out the factory token with what we know from the
		// given token.
		//
		f.token.assemblage_m = &token.assemblage_m;
		f.token.sheet_m = &token.sheet_m;
		f.token.layout_m = &token.layout_m;
		//
		// Update the token with the things that have been pushed
		// onto us.
		//
		for( factory_list_t::const_iterator i = _factories.begin();
			i != _factories.end(); i++ ) {
			//
			// If there is a factory or any pointers set here
			// then copy them over.
			//
			if( i->factory ) f.factory = i->factory;
			if( i->token.assemblage_m )
				f.token.assemblage_m = i->token.assemblage_m;
			if( i->token.sheet_m )
				f.token.sheet_m = i->token.sheet_m;
			if( i->token.layout_m )
				f.token.layout_m = i->token.layout_m;
		}
		return f;
	}
	adobe::widget_node_t factory::build( adobe::name_t	name,
		const adobe::dictionary_t&			params,
		const adobe::widget_node_t&			parent,
		const adobe::factory_token_t&			token ) {
		//
		// We need to build our token.
		//
		factory_t f( top( token ) );
		adobe::factory_token_t child_token( token.display_m,
			(f.token.assemblage_m ?
				*f.token.assemblage_m : token.assemblage_m),
			(f.token.layout_m ? *f.token.layout_m : token.layout_m),
			(f.token.sheet_m ? *f.token.sheet_m : token.sheet_m),
			token.notifier_m,
			token.widget_stream_m,
			token.show_window_signal_m,
			token.overlay_m,
			token.window_dirty_m );
		//
		// These factories know to push something onto our stack of
		// factory_ts.
		//
		if( name == adobe::static_name_t( "scroll" ) )
			return view::scroll_factory( params, parent,
				child_token, this );
		if( name == adobe::static_name_t( "generator" ) )
			return view::generator_factory( params, parent, 
				child_token, this );
		//
		// The other factories don't know to push anything special
		// onto the stack.
		//
		_factories.push_back( f );
		return f.factory( name, params, parent, child_token );
	}
};

